/*
 * acooly.cn Inc.
 * Copyright (c) 2016 All Rights Reserved.
 * create by zhike
 * date:2016年4月4日
 *
 */
package com.acooly.module.openapi.client.provider.shengpay.marshall;

import com.acooly.core.common.exception.BusinessException;
import com.acooly.core.utils.Reflections;
import com.acooly.core.utils.Strings;
import com.acooly.core.utils.validate.Validators;
import com.acooly.module.openapi.client.api.exception.ApiClientException;
import com.acooly.module.openapi.client.api.message.MessageFactory;
import com.acooly.module.openapi.client.api.util.Jsons;
import com.acooly.module.openapi.client.provider.shengpay.OpenAPIClientShengpayProperties;
import com.acooly.module.openapi.client.provider.shengpay.ShengpayConstants;
import com.acooly.module.openapi.client.provider.shengpay.domain.*;
import com.acooly.module.openapi.client.provider.shengpay.enums.ShengpayApiServiceType;
import com.acooly.module.openapi.client.provider.shengpay.exception.ShengpayProcessingException;
import com.acooly.module.openapi.client.provider.shengpay.utils.SignUtils;
import com.acooly.module.openapi.client.provider.shengpay.utils.StringHelper;
import com.acooly.module.safety.Safes;
import com.acooly.module.safety.key.KeyLoadManager;
import com.acooly.module.safety.signature.SignTypeEnum;
import com.acooly.module.safety.support.KeyPair;
import com.acooly.module.safety.support.KeyStoreInfo;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * @author zhike
 */
@Slf4j
public class ShengpayAbstractMarshall {

    @Autowired
    protected OpenAPIClientShengpayProperties openAPIClientFudianProperties;

    @Autowired
    protected KeyLoadManager keyStoreLoadManager;

    @Resource(name = "shengpayMessageFactory")
    private MessageFactory messageFactory;


    protected Map<String,String> doMarshall(ShengpayRequest source) {
        // pre
        source.setMerchantNo(getProperties().getMerchantNo());
        source.setService(ShengpayConstants.getServiceName(source));
        settingNotifyUrl(source);
        doVerifyParam(source);
        Map<String, String> signMap = getSignDataMap(source);
        String orignSignStr = StringHelper.getOrignSign(signMap);
        log.info("待签字符串：{}",orignSignStr);
        String sign = doSign(orignSignStr);
        signMap.put(ShengpayConstants.SIGN,sign);
        Map<String, String> datas = Maps.newTreeMap();
        datas.put(ShengpayConstants.SIGN_TYPE_KEY, ShengpayConstants.SHENGPAY_SIGN_TYPE);
        datas.put(ShengpayConstants.SIGN_MSG_KEY, sign);
        datas.put(ShengpayConstants.REQUEST_BODY_KEY, orignSignStr);
        return datas;
    }


    protected ShengpayResponse doUnMarshall(Map<String,String> message, String serviceName, boolean notify) {
        try {
            log.info("响应报文:{}", message);
            String signMsg = message.get(ShengpayConstants.SIGN_MSG_KEY);
            String verifySignStr = message.get(ShengpayConstants.RESPONSE_BODY_KEY);
            ShengpayResponse shengpayResponse = null;
            if (notify) {//通知报文不一样
                shengpayResponse = (ShengpayResponse) messageFactory.getNotify(serviceName);
                String notifyStr = message.get(ShengpayConstants.NOTIFY_DATA_JSON);
                if(Strings.isBlank(notifyStr)) {
                    throw new BusinessException("响应报文为空");
                }
                shengpayResponse = Jsons.parse(notifyStr, shengpayResponse.getClass());
                signMsg=shengpayResponse.getSignMsg();//得到签名结果
                verifySignStr=shengpayResponse.getSignStr();//得到验签原始数据
            } else {
                if(Strings.isBlank(verifySignStr)) {
                    throw new BusinessException("响应报文为空");
                }
                shengpayResponse = (ShengpayResponse) messageFactory.getResponse(serviceName);
                shengpayResponse = Jsons.parse(verifySignStr, shengpayResponse.getClass());
            }
            //验签
            doVerify(verifySignStr, signMsg);
            return shengpayResponse;
        } catch (Exception e) {
            throw new ShengpayProcessingException("解析报文错误:" + e.getMessage());
        }
    }

    public void settingNotifyUrl(ShengpayRequest apiMessage) {
        ShengpayApiMsg shengpayApiMsg = ShengpayConstants.getApiMsgInfo(apiMessage);
        if (Strings.isBlank(apiMessage.getNotifyUrl()) && shengpayApiMsg.service().getApiServiceType() != ShengpayApiServiceType.SYNC) {
            apiMessage.setNotifyUrl(ShengpayConstants.getCanonicalUrl(openAPIClientFudianProperties.getDomain(),
                    openAPIClientFudianProperties.getNotifyUrl()
                            + shengpayApiMsg.service().code()));
        }
        if (shengpayApiMsg.service().getApiServiceType() == ShengpayApiServiceType.REDIRECT && Strings.isBlank(apiMessage.getReturnUrl())) {
            throw new RuntimeException("跳转接口returnUrl是必须的");
        }
    }

    /**
     * 获取代签map
     *
     * @param source
     * @return
     */
    protected TreeMap<String, String> getSignDataMap(ShengpayRequest source) {
        TreeMap<String, String> signData = Maps.newTreeMap();
        Set<Field> fields = Reflections.getFields(source.getClass());
        String key = null;
        Object value = null;
        for (Field field : fields) {
            value = Reflections.getFieldValue(source, field.getName());
            key = field.getName();
            if (value == null) {
                continue;
            }
            if (Strings.isNotBlank((String) value)) {
                signData.put(key, (String) value);
            }
        }
        return signData;
    }

    /**
     * 获取验签字符串
     *
     * @param responseMessage
     * @return
     */
    protected String getVerifySignStr(JSONObject responseMessage) {
        Iterator<Map.Entry<String, Object>> sIterator = responseMessage.entrySet().iterator();
        StringBuffer sb=new StringBuffer();
        while(sIterator.hasNext()) {
            Map.Entry<String, Object> entry =sIterator.next();
            String key = entry.getKey();
            if(!Strings.equals(ShengpayConstants.SIGN,key)){
                sb.append("&").append(key).append("=").append(entry.getValue());
            }
        }
        String tobeVerify=sb.substring(1);
        return tobeVerify;
    }

    protected OpenAPIClientShengpayProperties getProperties() {
        return openAPIClientFudianProperties;
    }


    protected void doVerifyParam(ShengpayMessage source) {
        try {
            source.doCheck();
            Validators.assertJSR303(source);
        } catch (Exception e) {
            throw new ApiClientException(e.getMessage());
        }
    }

    protected String doSign(String waitForSign) {
        return Safes.getSigner(SignTypeEnum.Rsa).sign(waitForSign, getKeyPair());
    }

    protected void doVerify(String plain, String sign) {
        try {
            Safes.getSigner(SignTypeEnum.Rsa).verify(plain, getKeyPair(), sign);
            log.info("验签成功");
        }catch (Exception e) {
            throw new ApiClientException("验签失败："+e.getMessage());
        }
    }

    protected KeyPair getKeyPair() {
        return keyStoreLoadManager.load(ShengpayConstants.PROVIDER_DEF_PRINCIPAL, ShengpayConstants.PROVIDER_NAME);
    }


}
